﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Task_Parallel_Library
{
    [TestClass]
    public class TaskParallelism
    {
        [TestMethod]
        public void ParallelTasks()
        {
            var list = new BlockingCollection<int>();
            Parallel.Invoke(() => list.Add(1), () => list.Add(2));

            CollectionAssert.AreEqual(Enumerable.Range(1, 2).ToList(), list.OrderBy(x => x).ToList());
        }

        [TestMethod]
        public void UsingTaskArray()
        {

            Task<Double>[] taskArray = { Task<Double>.Factory.StartNew(() => DoComputation(1.0)),
                                     Task<Double>.Factory.StartNew(() => DoComputation(100.0)), 
                                     Task<Double>.Factory.StartNew(() => DoComputation(1000.0)) };

            var results = new Double[taskArray.Length];
            Double sum = 0;

            for (int i = 0; i < taskArray.Length; i++)
            {
                results[i] = taskArray[i].Result;
                Console.Write("{0:N1} {1}", results[i], i == taskArray.Length - 1 ? "= " : "+ ");
                sum += results[i];
            }
            Console.WriteLine("{0:N1}", sum);
        }

        private static Double DoComputation(Double start)
        {
            Double sum = 0;
            for (var value = start; value <= start + 10; value += .1)
                sum += value;

            return sum;
        }

        [TestMethod]
        public void WaitAll()
        {
            //initialize
            var items = Enumerable.Range(1, 10);
            var bag = new ConcurrentBag<int>();

            //execute
            var tasks = items.Select(x => Task.Factory.StartNew(() => bag.Add(x))).ToArray();
            Task.WaitAll(tasks);

            //assert            
            Assert.AreEqual(10, bag.Count);
        }

        [TestMethod]
        public void WhenAll()
        {
            //initialize
            var items = Enumerable.Range(1, 10);
            var bag = new ConcurrentBag<int>();

            //execute
            var container = Task.WhenAll(items.Select(x => Task.Factory.StartNew(() => bag.Add(x))));

            //assert            
            container.Wait();
            Assert.AreEqual(10, bag.Count);
        }

        [TestMethod]
        public void WhenAny()
        {
            //initialize
            var items = Enumerable.Range(1, 10);
            var random = new Random();

            //execute
            var container = Task.WhenAny(items.Select(x => Task.Factory.StartNew(() =>
            {
                Thread.Sleep(random.Next() % 100);
                return x;
                    
            })).ToArray());

            //assert                    
            var result = container.Result.Result;
            Assert.IsTrue(1 <= result && result <= 10);
        }
    }
}
